﻿#include "MirControl.h"
#include "../../Shared/Functions/Functions.h"
#include "../MirGraphics/DXManager.h"
#include "../Forms/Client.CMain.h"
#include "../Settings.h"
#include "../MirSounds/SoundManager.h"

using namespace Client::MirGraphics;
using namespace Client::MirSounds;
using namespace SlimDX;
using namespace SlimDX::Direct3D9;

namespace Client::MirControls
{

MirControl *MirControl::ActiveControl;
MirControl *MirControl::MouseControl;

    Point *MirControl::getDisplayLocation() const
    {
        return getParent() == nullptr ? getLocation() : Functions::Add(getParent()->getDisplayLocation(), getLocation());
    }

    Rectangle *MirControl::getDisplayRectangle() const
    {
        return new Rectangle(getDisplayLocation(), getSize());
    }

    bool MirControl::getGrayScale() const
    {
        return GrayScale;
    }

    void MirControl::setGrayScale(bool value)
    {
        GrayScale = value;
    }

    bool MirControl::getBlending() const
    {
        return Blending;
    }

    void MirControl::setBlending(bool value)
    {
        Blending = value;
    }

    float MirControl::getBlendingRate() const
    {
        return BlendingRate;
    }

    void MirControl::setBlendingRate(float value)
    {
        BlendingRate = value;
    }

    BlendMode MirControl::getBlendMode() const
    {
        return BlendMode;
    }

    void MirControl::setBlendMode(BlendMode value)
    {
        BlendMode = value;
    }

    Color *MirControl::getBackColour() const
    {
        return _backColour;
    }

    void MirControl::setBackColour(Color *value)
    {
        if (_backColour == value)
        {
            return;
        }
        _backColour = value;
        OnBackColourChanged();
    }

    void MirControl::OnBackColourChanged()
    {
        TextureValid = false;
        Redraw();
        if (BackColourChanged != nullptr)
        {
            BackColourChanged::Invoke(this, EventArgs::Empty);
        }
    }

    std::vector<Vector2*> MirControl::getBorderInfo() const
    {
        if (getSize() == getSize()->Empty)
        {
            return std::vector<Vector2*>();
        }

        if (BorderRectangle != getDisplayRectangle())
        {
            _borderInfo = std::vector<Vector2*>
            {
                new Vector2(getDisplayRectangle()->Left - 1, getDisplayRectangle()->Top - 1),
                new Vector2(getDisplayRectangle()->Right, getDisplayRectangle()->Top - 1),
                new Vector2(getDisplayRectangle()->Left - 1, getDisplayRectangle()->Top - 1),
                new Vector2(getDisplayRectangle()->Left - 1, getDisplayRectangle()->Bottom),
                new Vector2(getDisplayRectangle()->Left - 1, getDisplayRectangle()->Bottom),
                new Vector2(getDisplayRectangle()->Right, getDisplayRectangle()->Bottom),
                new Vector2(getDisplayRectangle()->Right, getDisplayRectangle()->Top - 1),
                new Vector2(getDisplayRectangle()->Right, getDisplayRectangle()->Bottom)
            };

            BorderRectangle = getDisplayRectangle();
        }
        return _borderInfo;
    }

    bool MirControl::getBorder() const
    {
        return _border;
    }

    void MirControl::setBorder(bool value)
    {
        if (_border == value)
        {
            return;
        }
        _border = value;
        OnBorderChanged();
    }

    void MirControl::OnBorderChanged()
    {
        Redraw();
        if (BorderChanged != nullptr)
        {
            BorderChanged::Invoke(this, EventArgs::Empty);
        }
    }

    Color *MirControl::getBorderColour() const
    {
        return _borderColour;
    }

    void MirControl::setBorderColour(Color *value)
    {
        if (_borderColour == value)
        {
            return;
        }
        _borderColour = value;
        OnBorderColourChanged();
    }

    void MirControl::OnBorderColourChanged()
    {
        Redraw();
        if (BorderColourChanged != nullptr)
        {
            BorderColourChanged::Invoke(this, EventArgs::Empty);
        }
    }

    bool MirControl::getDrawControlTexture() const
    {
        return _drawControlTexture;
    }

    void MirControl::setDrawControlTexture(bool value)
    {
        if (_drawControlTexture == value)
        {
            return;
        }
        _drawControlTexture = value;
        Redraw();
    }

    void MirControl::CreateTexture()
    {
        if (ControlTexture == nullptr || ControlTexture->Disposed)
        {
            DXManager::ControlList.push_back(this);
            ControlTexture = new Texture(DXManager::Device, getSize()->Width, getSize()->Height, 1, Usage::RenderTarget, Format::A8R8G8B8, Pool::Default);
            TextureSize = getSize();
        }

        Surface *oldSurface = DXManager::CurrentSurface;
        Surface *surface = ControlTexture->GetSurfaceLevel(0);
        DXManager::SetSurface(surface);
        DXManager::Device->Clear(ClearFlags::Target, getBackColour(), 0, 0);
        DXManager::SetSurface(oldSurface);

        TextureValid = true;
        surface->Dispose();
    }

    void MirControl::DisposeTexture()
    {
        if (ControlTexture == nullptr || ControlTexture->Disposed)
        {
            return;
        }

        ControlTexture->Dispose();
        ControlTexture = nullptr;
        TextureValid = false;
        TextureSize = getSize()->Empty;

        DXManager::ControlList.Remove(this);
    }

    std::vector<MirControl*> MirControl::getControls() const
    {
        return Controls;
    }

    void MirControl::setControls(const std::vector<MirControl*> &value)
    {
        Controls = value;
    }

    void MirControl::AddControl(MirControl *control)
    {
        getControls().push_back(control);
        OnControlAdded();
    }

    void MirControl::InsertControl(int index, MirControl *control)
    {
        if (control->getParent() != this)
        {
            control->setParent(nullptr);
            control->_parent = this;
        }

        if (index >= getControls().size())
        {
            getControls().push_back(control);
        }
        else
        {
            getControls().Insert(index, control);
            OnControlAdded();
        }
    }

    void MirControl::RemoveControl(MirControl *control)
    {
        getControls().Remove(control);
        OnControlRemoved();
    }

    void MirControl::OnControlAdded()
    {
        Redraw();
        if (ControlAdded != nullptr)
        {
            ControlAdded::Invoke(this, EventArgs::Empty);
        }
    }

    void MirControl::OnControlRemoved()
    {
        Redraw();
        if (ControlRemoved != nullptr)
        {
            ControlRemoved::Invoke(this, EventArgs::Empty);
        }
    }

    bool MirControl::getEnabled() const
    {
        return getParent() == nullptr ? _enabled : getParent()->getEnabled() && _enabled;
    }

    void MirControl::setEnabled(bool value)
    {
        if (_enabled == value)
        {
            return;
        }
        _enabled = value;
        OnEnabledChanged();
    }

    void MirControl::OnEnabledChanged()
    {
        Redraw();

        if (EnabledChanged != nullptr)
        {
            EnabledChanged::Invoke(this, EventArgs::Empty);
        }

        if (!getEnabled() && ActiveControl == this)
        {
            ActiveControl->Deactivate();
        }

        if (!getControls().empty())
        {
            for (auto control : getControls())
            {
                control->OnEnabledChanged();
            }
        }
    }

    Color *MirControl::getForeColour() const
    {
        return _foreColour;
    }

    void MirControl::setForeColour(Color *value)
    {
        if (_foreColour == value)
        {
            return;
        }
        _foreColour = value;
        OnForeColourChanged();
    }

    void MirControl::OnForeColourChanged()
    {
        TextureValid = false;
        if (ForeColourChanged != nullptr)
        {
            ForeColourChanged::Invoke(this, EventArgs::Empty);
        }
    }

    Point *MirControl::getLocation() const
    {
        return _location;
    }

    void MirControl::setLocation(Point *value)
    {
        if (_location == value)
        {
            return;
        }
        _location = value;
        OnLocationChanged();
    }

    void MirControl::OnLocationChanged()
    {
        Redraw();
        if (!getControls().empty())
        {
            for (int i = 0; i < getControls().size(); i++)
            {
                getControls()[i]->OnLocationChanged();
            }
        }

        if (LocationChanged != nullptr)
        {
            LocationChanged::Invoke(this, EventArgs::Empty);
        }
    }

    std::string MirControl::getHint() const
    {
        return _hint;
    }

    void MirControl::setHint(const std::string &value)
    {
        if (_hint == value)
        {
            return;
        }

        _hint = value;
        OnHintChanged(EventArgs::Empty);
    }

    void MirControl::OnHintChanged(EventArgs *e)
    {
        Redraw();
        if (HintChanged != nullptr)
        {
            HintChanged::Invoke(this, e);
        }
    }

    bool MirControl::getModal() const
    {
        return _modal;
    }

    void MirControl::setModal(bool value)
    {
        if (_modal == value)
        {
            return;
        }
        _modal = value;
        OnModalChanged();
    }

    void MirControl::OnModalChanged()
    {
        Redraw();
        if (ModalChanged != nullptr)
        {
            ModalChanged::Invoke(this, EventArgs::Empty);
        }
    }

    bool MirControl::getMovable() const
    {
        return _movable;
    }

    void MirControl::setMovable(bool value)
    {
        if (_movable == value)
        {
            return;
        }
        _movable = value;
        OnMovableChanged();
    }

    void MirControl::OnMovableChanged()
    {
        Redraw();
        if (MovableChanged != nullptr)
        {
            MovableChanged::Invoke(this, EventArgs::Empty);
        }
    }

    bool MirControl::getNotControl() const
    {
        return _notControl;
    }

    void MirControl::setNotControl(bool value)
    {
        if (_notControl == value)
        {
            return;
        }
        _notControl = value;
        OnNotControlChanged();
    }

    void MirControl::OnNotControlChanged()
    {
        Redraw();
        if (NotControlChanged != nullptr)
        {
            NotControlChanged::Invoke(this, EventArgs::Empty);
        }
    }

    float MirControl::getOpacity() const
    {
        return _opacity;
    }

    void MirControl::setOpacity(float value)
    {
        if (value > 1.0F)
        {
            value = 1.0F;
        }
        if (value < 0.0F)
        {
            value = 0;
        }

        if (_opacity == value)
        {
            return;
        }

        _opacity = value;
        OnOpacityChanged();
    }

    void MirControl::OnOpacityChanged()
    {
        Redraw();
        if (OpacityChanged != nullptr)
        {
            OpacityChanged::Invoke(this, EventArgs::Empty);
        }
    }

    MirControl *MirControl::getParent() const
    {
        return _parent;
    }

    void MirControl::setParent(MirControl *value)
    {
        if (_parent == value)
        {
            return;
        }

        if (_parent != nullptr)
        {
            _parent->RemoveControl(this);
        }
        _parent = value;
        if (_parent != nullptr)
        {
            _parent->AddControl(this);
        }
        OnParentChanged();
    }

    void MirControl::OnParentChanged()
    {
        OnLocationChanged();
        if (ParentChanged != nullptr)
        {
            ParentChanged::Invoke(this, EventArgs::Empty);
        }
    }

    Size *MirControl::getSize() const
    {
        return _size;
    }

    void MirControl::setSize(Size *value)
    {
        if (_size == value)
        {
            return;
        }
        _size = value;
        OnSizeChanged();
    }

    Size *MirControl::getTrueSize() const
    {
        return _size;
    }

    void MirControl::OnSizeChanged()
    {
        TextureValid = false;
        Redraw();

        if (SizeChanged != nullptr)
        {
            SizeChanged::Invoke(this, EventArgs::Empty);
        }
    }

    int MirControl::getSound() const
    {
        return _sound;
    }

    void MirControl::setSound(int value)
    {
        if (_sound == value)
        {
            return;
        }
        _sound = value;
        OnSoundChanged();
    }

    void MirControl::OnSoundChanged()
    {
        if (SoundChanged != nullptr)
        {
            SoundChanged::Invoke(this, EventArgs::Empty);
        }
    }

    bool MirControl::getSort() const
    {
        return _sort;
    }

    void MirControl::setSort(bool value)
    {
        if (_sort == value)
        {
            return;
        }
        _sort = value;
        OnSortChanged();
    }

    void MirControl::OnSortChanged()
    {
        Redraw();
        if (SortChanged != nullptr)
        {
            SortChanged::Invoke(this, EventArgs::Empty);
        }
    }

    void MirControl::TrySort()
    {
        if (getParent() == nullptr)
        {
            return;
        }

        getParent()->TrySort();

        if (getParent()->getControls()[getParent()->getControls().size() - 1] == this)
        {
            return;
        }

        if (!getSort())
        {
            return;
        }

        getParent()->getControls().Remove(this);
        getParent()->getControls().push_back(this);

        Redraw();
    }

    bool MirControl::getVisible() const
    {
        return getParent() == nullptr ? _visible : getParent()->getVisible() && _visible;
    }

    void MirControl::setVisible(bool value)
    {
        if (_visible == value)
        {
            return;
        }
        _visible = value;
        OnVisibleChanged();
    }

    void MirControl::OnVisibleChanged()
    {
        Redraw();
        if (VisibleChanged != nullptr)
        {
            VisibleChanged::Invoke(this, EventArgs::Empty);
        }

        Moving = false;
        _movePoint = Point::Empty;

        if (getSort() && getParent() != nullptr)
        {
            getParent()->getControls().Remove(this);
            getParent()->getControls().push_back(this);
        }

        if (MouseControl == this && !getVisible())
        {
            Dehighlight();
            Deactivate();
        }
        else if (IsMouseOver(CMain::MPoint))
        {
            Highlight();
        }


        if (!getControls().empty())
        {
            for (auto control : getControls())
            {
                control->OnVisibleChanged();
            }
        }
    }

    void MirControl::OnBeforeShown()
    {
        if (HasShown)
        {
            return;
        }

        if (getVisible() && IsMouseOver(CMain::MPoint))
        {
            Highlight();
        }

        if (BeforeShown != nullptr)
        {
            BeforeShown::Invoke(this, EventArgs::Empty);
        }
    }

    void MirControl::OnShown()
    {
        if (HasShown)
        {
            return;
        }

        if (Shown != nullptr)
        {
            Shown::Invoke(this, EventArgs::Empty);
        }

        HasShown = true;
    }

    void MirControl::MultiLine()
    {
    }

    Point *MirControl::getCenter() const
    {
        return new Point((Settings::ScreenWidth - getSize()->Width) / 2, (Settings::ScreenHeight - getSize()->Height) / 2);
    }

    Point *MirControl::getLeft() const
    {
        return new Point(0, (Settings::ScreenHeight - getSize()->Height) / 2);
    }

    Point *MirControl::getTop() const
    {
        return new Point((Settings::ScreenWidth - getSize()->Width) / 2, 0);
    }

    Point *MirControl::getRight() const
    {
        return new Point(Settings::ScreenWidth - getSize()->Width, (Settings::ScreenHeight - getSize()->Height) / 2);
    }

    Point *MirControl::getBottom() const
    {
        return new Point((Settings::ScreenWidth - getSize()->Width) / 2, Settings::ScreenHeight - getSize()->Height);
    }

    Point *MirControl::getTopLeft() const
    {
        return new Point(0, 0);
    }

    Point *MirControl::getTopRight() const
    {
        return new Point(Settings::ScreenWidth - getSize()->Width, 0);
    }

    Point *MirControl::getBottomRight() const
    {
        return new Point(Settings::ScreenWidth - getSize()->Width, Settings::ScreenHeight - getSize()->Height);
    }

    Point *MirControl::getBottomLeft() const
    {
        return new Point(0, Settings::ScreenHeight - getSize()->Height);
    }

    void MirControl::BringToFront()
    {
        if (getParent() == nullptr)
        {
            return;
        }
        int index = VectorHelper::indexOf(_parent->getControls(), this);
        if (index == _parent->getControls().size() - 1)
        {
            return;
        }

        _parent->getControls().erase(_parent->getControls().begin() + index);
        _parent->getControls().push_back(this);
        Redraw();
    }

    MirControl::MirControl()
    {
        setControls(std::vector<MirControl*>());
        _opacity = 1.0F;
        _enabled = true;
        _foreColour = Color::White;
        _visible = true;
        _sound = SoundList::None;
    }

    void MirControl::Show()
    {
        if (getVisible())
        {
            return;
        }
        setVisible(true);
    }

    void MirControl::Hide()
    {
        if (!getVisible())
        {
            return;
        }
        setVisible(false);
    }

    void MirControl::Draw()
    {
        if (isDisposed() || !getVisible() || getSize()->Width > Settings::ScreenWidth || getSize()->Height > Settings::ScreenHeight)
        {
            return;
        }

        OnBeforeShown();

        BeforeDrawControl();
        DrawControl();
        DrawChildControls();
        DrawBorder();
        AfterDrawControl();

        CleanTime = CMain::Time + Settings::CleanDelay;

        OnShown();
    }

    void MirControl::BeforeDrawControl()
    {
        if (BeforeDraw != nullptr)
        {
            BeforeDraw::Invoke(this, EventArgs::Empty);
        }
    }

    void MirControl::DrawControl()
    {
        if (!getDrawControlTexture())
        {
            return;
        }

        if (!TextureValid)
        {
            CreateTexture();
        }

        if (ControlTexture == nullptr || ControlTexture->Disposed)
        {
            return;
        }

        float oldOpacity = DXManager::Opacity;

        DXManager::SetOpacity(getOpacity());
        Rectangle tempVar(0, 0, getSize()->Width, getSize()->Height);
        Vector3 tempVar2(static_cast<float>(getDisplayLocation()->X), static_cast<float>(getDisplayLocation()->Y), 0.0f);
        DXManager::Sprite->Draw(ControlTexture, &tempVar, Vector3::Zero, &tempVar2, Color::White);
        DXManager::SetOpacity(oldOpacity);

        CleanTime = CMain::Time + Settings::CleanDelay;
    }

    void MirControl::DrawChildControls()
    {
        if (!getControls().empty())
        {
            for (int i = 0; i < getControls().size(); i++)
            {
                if (getControls()[i] != nullptr)
                {
                    getControls()[i]->Draw();
                }
            }
        }
    }

    void MirControl::DrawBorder()
    {
        if (!getBorder() || getBorderInfo().empty())
        {
            return;
        }
        DXManager::Sprite->Flush();
        DXManager::Line->Draw(getBorderInfo(), _borderColour);
    }

    void MirControl::AfterDrawControl()
    {
        if (AfterDraw != nullptr)
        {
            AfterDraw::Invoke(this, EventArgs::Empty);
        }
    }

    void MirControl::Deactivate()
    {
        if (ActiveControl != this)
        {
            return;
        }

        ActiveControl = nullptr;
        Moving = false;
        _movePoint = Point::Empty;
    }

    void MirControl::Dehighlight()
    {
        if (MouseControl != this)
        {
            return;
        }
        MouseControl->OnMouseLeave();
        MouseControl = nullptr;
    }

    void MirControl::Activate()
    {
        if (ActiveControl == this)
        {
            return;
        }

        if (ActiveControl != nullptr)
        {
            ActiveControl->Deactivate();
        }

        ActiveControl = this;
    }

    void MirControl::Highlight()
    {
        if (MouseControl == this)
        {
            return;
        }
        if (getNotControl())
        {

        }
        if (MouseControl != nullptr)
        {
            MouseControl->Dehighlight();
        }

        if (ActiveControl != nullptr && ActiveControl != this)
        {
            return;
        }

        OnMouseEnter();
        MouseControl = this;
    }

    bool MirControl::IsMouseOver(Point *p)
    {
        return getVisible() && (getDisplayRectangle()->Contains(p) || Moving || getModal()) && !getNotControl();
    }

    void MirControl::OnMouseEnter()
    {
        if (!_enabled)
        {
            return;
        }

        Redraw();

        if (MouseEnter != nullptr)
        {
            MouseEnter::Invoke(this, EventArgs::Empty);
        }
    }

    void MirControl::OnMouseLeave()
    {
        if (!_enabled)
        {
            return;
        }

        Redraw();

        if (MouseLeave != nullptr)
        {
            MouseLeave::Invoke(this, EventArgs::Empty);
        }
    }

    void MirControl::OnMouseClick(MouseEventArgs *e)
    {
        if (!getEnabled())
        {
            return;
        }

        if (getSound() != SoundList::None)
        {
            SoundManager::PlaySound(getSound());
        }

        if (Click != nullptr)
        {
            InvokeMouseClick(e);
        }
    }

    void MirControl::OnMouseDoubleClick(MouseEventArgs *e)
    {
        if (!getEnabled())
        {
            return;
        }

        if (DoubleClick != nullptr)
        {
            if (getSound() != SoundList::None)
            {
                SoundManager::PlaySound(getSound());
            }
            InvokeMouseDoubleClick(e);
        }
        else
        {
            OnMouseClick(e);
        }
    }

    void MirControl::InvokeMouseClick(EventArgs *e)
    {
        if (Click != nullptr)
        {
            Click::Invoke(this, e);
        }
    }

    void MirControl::InvokeMouseDoubleClick(EventArgs *e)
    {
        DoubleClick::Invoke(this, e);
    }

    void MirControl::OnMouseMove(MouseEventArgs *e)
    {
        if (!_enabled)
        {
            return;
        }


        if (Moving)
        {
            Point *tempPoint = Functions::Subtract(CMain::MPoint, _movePoint);

            if (getParent() == nullptr)
            {
                if (tempPoint->Y + getTrueSize()->Height > Settings::ScreenHeight)
                {
                    tempPoint->Y = Settings::ScreenHeight - getTrueSize()->Height - 1;
                }

                if (tempPoint->X + getTrueSize()->Width > Settings::ScreenWidth)
                {
                    tempPoint->X = Settings::ScreenWidth - getTrueSize()->Width - 1;
                }
            }
            else
            {
                if (tempPoint->Y + getTrueSize()->Height > getParent()->getTrueSize()->Height)
                {
                    tempPoint->Y = getParent()->getTrueSize()->Height - getTrueSize()->Height;
                }

                if (tempPoint->X + getTrueSize()->Width > getParent()->getTrueSize()->Width)
                {
                    tempPoint->X = getParent()->getTrueSize()->Width - getTrueSize()->Width;
                }
            }

            if (tempPoint->X < 0)
            {
                tempPoint->X = 0;
            }
            if (tempPoint->Y < 0)
            {
                tempPoint->Y = 0;
            }

            setLocation(tempPoint);
            if (OnMoving != nullptr)
            {
                OnMoving::Invoke(this, e);
            }
            return;
        }

        if (!getControls().empty())
        {
            for (int i = getControls().size() - 1; i >= 0; i--)
            {
                if (getControls()[i]->IsMouseOver(CMain::MPoint))
                {
                    getControls()[i]->OnMouseMove(e);
                    return;
                }
            }
        }

        Highlight();

        if (MouseMove != nullptr)
        {
            MouseMove::Invoke(this, e);
        }
    }

    void MirControl::OnMouseDown(MouseEventArgs *e)
    {
        if (!_enabled)
        {
            return;
        }

        Activate();

        TrySort();

        if (_movable)
        {
            Moving = true;
            _movePoint = Functions::Subtract(CMain::MPoint, getLocation());
        }

        if (MouseDown != nullptr)
        {
            MouseDown::Invoke(this, e);
        }
    }

    void MirControl::OnMouseUp(MouseEventArgs *e)
    {
        if (!_enabled)
        {
            return;
        }

        if (Moving)
        {
            Moving = false;
            _movePoint = Point::Empty;
        }

        if (ActiveControl != nullptr)
        {
            ActiveControl->Deactivate();
        }

        if (MouseUp != nullptr)
        {
            MouseUp::Invoke(this, e);
        }
    }

    void MirControl::OnMouseWheel(MouseEventArgs *e)
    {
        if (!getEnabled())
        {
            return;
        }

        if (MouseWheel != nullptr)
        {
            MouseWheel::Invoke(this, e);
        }
    }

    void MirControl::OnKeyPress(KeyPressEventArgs *e)
    {
        if (!_enabled)
        {
            return;
        }

        if (!getControls().empty())
        {
            for (int i = getControls().size() - 1; i >= 0; i--)
            {
                if (e->Handled)
                {
                    return;
                }
                else
                {
                    getControls()[i]->OnKeyPress(e);
                }
            }
        }

        if (KeyPress == nullptr)
        {
            return;
        }
        KeyPress::Invoke(this, e);
    }

    void MirControl::OnKeyDown(KeyEventArgs *e)
    {
        if (!_enabled)
        {
            return;
        }

        if (!getControls().empty())
        {
            for (int i = getControls().size() - 1; i >= 0; i--)
            {
                if (e->Handled)
                {
                    return;
                }
                else
                {
                    getControls()[i]->OnKeyDown(e);
                }
            }
        }

        if (KeyDown == nullptr)
        {
            return;
        }
        KeyDown::Invoke(this, e);
    }

    void MirControl::OnKeyUp(KeyEventArgs *e)
    {
        if (!_enabled)
        {
            return;
        }

        if (!getControls().empty())
        {
            for (int i = getControls().size() - 1; i >= 0; i--)
            {
                if (e->Handled)
                {
                    return;
                }
                else
                {
                    getControls()[i]->OnKeyUp(e);
                }
            }
        }

        if (KeyUp == nullptr)
        {
            return;
        }
        KeyUp::Invoke(this, e);
    }

    void MirControl::Redraw()
    {
        if (getParent() != nullptr)
        {
            getParent()->Redraw();
        }

    }

    System::Drawing::Font *MirControl::ScaleFont(System::Drawing::Font *font)
    {
        return new System::Drawing::Font(font->Name, font->Size * 96.0f / CMain::Graphics->DpiX, font->Style);
    }

    bool MirControl::isDisposed() const
    {
        return IsDisposed;
    }

    void MirControl::setDisposed(bool value)
    {
        IsDisposed = value;
    }

    void MirControl::Dispose()
    {
        delete _backColour;
        delete BorderRectangle;
        delete _borderColour;
        delete ControlTexture;
        delete TextureSize;
        delete _foreColour;
        delete _location;
        delete _movePoint;
        delete _parent;
        delete _size;
        if (isDisposed())
        {
            return;
        }
        Dispose(true);
    }

    void MirControl::Dispose(bool disposing)
    {
        if (disposing)
        {
            if (Disposing != nullptr)
            {
                Disposing::Invoke(this, EventArgs::Empty);
            }

            Disposing->addListener("nullptr", nullptr);

            BackColourChanged->addListener("nullptr", nullptr);
            _backColour = Color::Empty;

            BorderChanged->addListener("nullptr", nullptr);
            _border = false;
            BorderRectangle = Rectangle::Empty;
            _borderInfo = std::vector<Vector2*>();

            BorderColourChanged->addListener("nullptr", nullptr);
            _borderColour = Color::Empty;

            setDrawControlTexture(false);
            if (ControlTexture != nullptr && !ControlTexture->Disposed)
            {
                ControlTexture->Dispose();
            }
            ControlTexture = nullptr;
            TextureValid = false;

            ControlAdded = nullptr;
            ControlRemoved->addListener("nullptr", nullptr);

            if (!getControls().empty())
            {
                for (int i = getControls().size() - 1; i >= 0; i--)
                {
                    if (getControls()[i] != nullptr && !getControls()[i]->isDisposed())
                    {
                        getControls()[i]->Dispose();
                    }
                }

                setControls(std::vector<MirControl*>());
            }
            _enabled = false;
            EnabledChanged->addListener("nullptr", nullptr);

            HasShown = false;

            BeforeDraw = nullptr;
            AfterDraw = nullptr;
            Shown = nullptr;
            BeforeShown = nullptr;

            Click = nullptr;
            DoubleClick = nullptr;
            MouseEnter = nullptr;
            MouseLeave = nullptr;
            MouseMove = nullptr;
            MouseDown = nullptr;
            MouseUp->addListener("nullptr", nullptr);
            MouseWheel = nullptr;

            KeyPress->addListener("nullptr", nullptr);
            KeyUp->addListener("nullptr", nullptr);
            KeyDown = nullptr;

            ForeColourChanged->addListener("nullptr", nullptr);
            _foreColour = Color::Empty;

            LocationChanged->addListener("nullptr", nullptr);
            _location = Point::Empty;

            ModalChanged->addListener("nullptr", nullptr);
            _modal = false;

            MovableChanged->addListener("nullptr", nullptr);
            _movePoint = Point::Empty;
            Moving = false;
            OnMoving->addListener("nullptr", nullptr);
            _movable = false;

            NotControlChanged->addListener("nullptr", nullptr);
            _notControl = false;

            OpacityChanged->addListener("nullptr", nullptr);
            _opacity = 0.0F;

            if (getParent() != nullptr && !getParent()->getControls().empty())
            {
                getParent()->getControls().Remove(this);
            }
            ParentChanged->addListener("nullptr", nullptr);
            _parent = nullptr;

            SizeChanged->addListener("nullptr", nullptr);
            _size = getSize()->Empty;

            SoundChanged->addListener("nullptr", nullptr);
            _sound = 0;

            VisibleChanged->addListener("nullptr", nullptr);
            _visible = false;

            if (ActiveControl == this)
            {
                ActiveControl = nullptr;
            }
            if (MouseControl == this)
            {
                MouseControl = nullptr;
            }
        }

        setDisposed(true);
    }
}
